package com.xneure.code;

import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.xneure.code.log.ILog;
import com.xneure.code.log.LogWatcher;
import com.xneure.code.log.ILog.Level;
import com.xneure.code.log.LogManage;
import com.xneure.code.plantask.CountTask;
import com.xneure.code.plantask.TimerEvent;
import com.xneure.utils.ObjectUtil;
import com.xneure.utils.SpringUtil;
import com.xneure.utils.bean.Caller;

@Controller
@RequestMapping("/*/monitoring/log")
public class LogCheckPoint extends LogWatcher implements InitializingBean{
	private SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
	private StringBuilder tmpLog = new StringBuilder();
	private String cls;
	private String method;
	private String content;
	private boolean isStop = true;
	private int waitCount = -1;
	private CountTask task;

	@ResponseBody
	@RequestMapping(method = RequestMethod.GET)
	public void logPage(HttpServletRequest request,HttpServletResponse response){
	}

	@ResponseBody
	@RequestMapping(value = "/page",method = RequestMethod.GET)
	public void page(HttpServletRequest request,HttpServletResponse response){
		response.setContentType("text/html");
		ClassLoader cl = this.getClass().getClassLoader();
		InputStream is = cl.getResourceAsStream("META-INF/resources/LogCheckPoint.jsp");
		ServletOutputStream pr;
		try{
			Map<String,Object> par = SpringUtil.parseRequestParam();
			pr = response.getOutputStream();
			StringBuffer requestURL = request.getRequestURL();
			requestURL.setLength(requestURL.length() - (requestURL.length() - requestURL.indexOf("/monitoring")) + 1);
			String tmp = "<script type=\"text/javascript\"> var currUrl = '" + requestURL.toString() + "';";
			if(null != par && par.containsKey("suffix")){
				tmp = tmp + "var suffix= '" + par.get("suffix") + "'; </script>";
			}else{
				tmp = tmp + "var suffix= ''; </script>";
			}
			pr.write(tmp.getBytes());
			byte[] bs = new byte[1024 * 5];
			int rl = 0;
			while((rl = is.read(bs)) != -1){
				pr.write(bs,0,rl);
			}
			pr.flush();
		}catch(Exception e){
		}
	}

	@RequestMapping(value = "/start",method = RequestMethod.GET)
	@ResponseBody
	public void start(HttpServletResponse response){
		if(isStop){
			return;
		}
		response.setContentType("text/html");
		PrintWriter pr;
		try{
			pr = response.getWriter();
			String log = getLog();
			if(ObjectUtil.isNotNull(log)){
				pr.print(log);
				pr.flush();
			}
		}catch(Exception e){
		}
	}

	private void startTiming(){
		if(task == null){
			task = new CountTask(-1);
			task.setRunEvent(new TimerEvent(){
				@Override
				public void tick(){
					if(waitCount > -1){
						if(++waitCount > 3){
							stop(true);
						}
					}
				}
			});
		}
		task.setInterval(10000);
		if(isStop){
			task.stop();
		}else{
			task.start();
		}
	}

	private void emptyLog(){
		synchronized(tmpLog){
			if(tmpLog.length() > 0){
				tmpLog.delete(0,tmpLog.length() - 1);
			}
		}
	}

	@RequestMapping(value = "/filter",method = RequestMethod.GET)
	@ResponseBody
	public void filter(@RequestParam(value = "level",required = false) Level level,@RequestParam(value = "cls",required = false) String cls,
			@RequestParam(value = "method",required = false) String method,@RequestParam(value = "content",required = false) String content)
	{
		emptyLog();
		this.level = null == level ? Level.ALL : level;
		this.cls = "".equals(cls) ? null : cls;
		this.method = "".equals(method) ? null : cls;
		this.content = "".equals(content) ? null : cls;
	}

	@RequestMapping(value = "/stop",method = RequestMethod.GET)
	@ResponseBody
	public boolean stop(@RequestParam(value = "isStop",required = false) boolean isStop){
		emptyLog();
		waitCount = -1;
		this.isStop = isStop;
		this.cls = null;
		this.method = null;
		this.content = null;
		startTiming();
		return this.isStop;
	}

	@RequestMapping(value = "/getLog",produces = "text/html;charset=UTF-8",method = RequestMethod.GET)
	@ResponseBody
	public String getLog(){
		if(isStop){
			return null;
		}
		synchronized(tmpLog){
			waitCount = 0;
			try{
				if(tmpLog.length() > 0){
					return tmpLog.toString();
				}else{
					return null;
				}
			}finally{
				tmpLog.setLength(0);
			}
		}
	}

	@Override
	public void handle(ILog il,Level le,String log){
		if(isStop || log.contains("monitoring/log/")){
			return;
		}
		if(null != this.level){
			if(this.level != Level.ALL && le != this.level){
				return;
			}
		}
		if(null != this.content){
			if(log.contains(this.content) == false){
				return;
			}
		}
		synchronized(tmpLog){
			Caller caller = il.getCaller();
			if(null != this.cls){
				if(caller.getClassName().contains(this.cls) == false){
					return;
				}
			}
			if(null != this.method){
				if(caller.getMethodName().contains(this.method) == false){
					return;
				}
			}
			if(il.isSysHandle() == false){
				this.tmpLog.append(formatter.format(System.currentTimeMillis()));
				this.tmpLog.append(" ");
				this.tmpLog.append(le.name());
				this.tmpLog.append(" ");
				this.tmpLog.append(caller.getClassName().concat(" 行：").concat(String.valueOf(caller.getLineNumber())));
				this.tmpLog.append(" ");
			}
			this.tmpLog.append(log);
		}
	}

	@Override
	public void saveLog(){
	}

	@Override
	public void afterPropertiesSet() throws Exception{
		LogManage.registerWatcher(this);
	}
}
